using JavaVirtualMachine;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;

public static class AndroidNativeMethodFactory
{
    private static Dictionary<string, Type> sDictionary = null;
    public static long TickCount;
    static AndroidNativeMethodFactory()
    {
        Initialize();
    }
    private static void Initialize()
    {
        TickCount = Environment.TickCount;
        sDictionary = new Dictionary<string, Type>();
        Type[] types = typeof(AndroidNativeMethodFactory).Assembly.GetTypes();
        foreach (var cls in types)
        {
            if (!cls.IsClass) continue;
            if (!cls.GetInterfaces().Contains(typeof(AndroidINativeMethod))) continue;
            if (cls.GetConstructor(new Type[0]) == null) continue;

            var attr = (AndroidNativeMethodAttribute)cls.GetCustomAttributes(typeof(AndroidNativeMethodAttribute), false).FirstOrDefault();
            if (attr == null) continue;
            sDictionary.Add(attr.ClassName, cls);
        }
    }

    public static AndroidINativeMethod ExecuteNativeMethod(string className, string thisFuncName, string thisDescriptor, HeapObject thisObj, int[] args,
        Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        if (sDictionary == null)
            Initialize();
        Type type;
        string key = className;
        string Descriptor = thisFuncName + "-" + thisDescriptor;
        if (!sDictionary.TryGetValue(key, out type))
        {
            return null;
        }
        System.Reflection.MethodInfo[] info=type.GetMethods();

        AndroidINativeMethod tag = null;
        foreach (var item in info)
        {
            var attr = (AndroidNativeMethodAttribute)item.GetCustomAttributes(typeof(AndroidNativeMethodAttribute), false).FirstOrDefault();
            if (attr != null)
            {
                if(attr.Descriptor== Descriptor)
                {
                    tag = (AndroidINativeMethod)Activator.CreateInstance(type);
                    item.Invoke(tag,new object[] { thisObj, args, MethodFrameStack, GlobalStack });
                    break;
                }
            }
        }
        return tag;
    }
}

public interface AndroidINativeMethod
{
    //public void Execute(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack);
}

public class AndroidNativeMethodAttribute : Attribute
{
    public string Descriptor;
    public string ClassName;

    public AndroidNativeMethodAttribute(string className,string descriptor=null)
    {
        Descriptor = descriptor;
        ClassName = className;
    }
}

#region Log
[AndroidNativeMethodAttribute("android/util/Log")]
public class Log : AndroidINativeMethod
{
    [AndroidNativeMethodAttribute("android/util/Log", "isLoggable-(Ljava/lang/String;I)Z")]
    public void isLoggable(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        string info = JavaHelper.ReadJavaString(args[0]);
        Console.WriteLine("Log:"+info +":"+args[1]);

        JavaHelper.ReturnVoid(MethodFrameStack, GlobalStack);
    }

    [AndroidNativeMethodAttribute("android/util/Log", "println_native-(IILjava/lang/String;Ljava/lang/String;)I")]
    public void println_native(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        string info = JavaHelper.ReadJavaString(args[2]);
        string info2 = JavaHelper.ReadJavaString(args[3]);
        Console.WriteLine("println:" + info + ":" +info2);

        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack,0);
    }
}
#endregion

#region SystemProperties
[AndroidNativeMethodAttribute("android/os/SystemProperties")]
public class SystemProperties : AndroidINativeMethod
{
    public static Dictionary<string, string> properties = new Dictionary<string, string>()
    {   { "ro.product.cpu.abilist64","arm64-v8a" },
        { "ro.product.cpu.abilist32","armeabi,armeabi-v7a" },
        { "ro.build.id","GRI40" },
        { "ro.build.display.id","GRJ22" },
        { "ro.build.version.incremental","eng.buildbot.20110619.060228" },
        { "ro.build.version.sdk","17" },
        { "ro.build.version.codename","REL" },
        { "ro.build.version.release","4.4.0" },
        { "ro.build.date","Sun Jun 19 06:02:58 UTC 2011" },
        { "ro.build.date.utc","0" },
        { "ro.build.type","user" },
        { "ro.build.version.all_codenames","REL" },
    };
    [AndroidNativeMethodAttribute("android/os/SystemProperties", "native_get-(Ljava/lang/String;)Ljava/lang/String;")]
    public void native_get(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        string key = JavaHelper.ReadJavaString(args[0]);
        string value = "";
        if (properties.ContainsKey(key))
            value = properties[key];
        int def = JavaHelper.CreateJavaStringLiteral(value);
        Console.WriteLine("SystemProperties.getString(" + key + "," + def+")");

        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack, def);
    }

    [AndroidNativeMethodAttribute("android/os/SystemProperties", "native_get-(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;")]
    public void native_get2(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        string key = JavaHelper.ReadJavaString(args[0]);
        string def = JavaHelper.ReadJavaString(args[1]);

        Console.WriteLine("SystemProperties.getString(" + key + "," + def + ")");

        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack, args[1]);
    }

    [AndroidNativeMethodAttribute("android/os/SystemProperties", "native_get_boolean-(Ljava/lang/String;Z)Z")]
    public void native_get_boolean(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        string key = JavaHelper.ReadJavaString(args[0]);
        int def = args[1];

        Console.WriteLine("SystemProperties.getBoolean(" + key + "," + def + ")");

        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack, def);
    }

    [AndroidNativeMethodAttribute("android/os/SystemProperties", "native_get_int-(Ljava/lang/String;I)I")]
    public void native_get_int(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        string key = JavaHelper.ReadJavaString(args[0]);
        int def = args[1];

        Console.WriteLine("SystemProperties.getInt(" + key + "," + def + ")");

        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack, def);
    }

    [AndroidNativeMethodAttribute("android/os/SystemProperties", "native_get_long-(Ljava/lang/String;L)L")]
    public void native_get_long(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        string key = JavaHelper.ReadJavaString(args[0]);
        long def = (args[1],args[2]).ToLong();

        Console.WriteLine("SystemProperties.getLong(" + key + "," + def + ")");

        JavaHelper.ReturnLargeValue(MethodFrameStack, GlobalStack, def);
    }

    [AndroidNativeMethodAttribute("android/os/SystemProperties", "native_set-(Ljava/lang/String;;Ljava/lang/String;)V")]
    public void native_set(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        string key = JavaHelper.ReadJavaString(args[0]);
        string def = JavaHelper.ReadJavaString(args[1]);
        if (properties.ContainsKey(key))
            properties[key] = def;
        else
            properties.Add(key, def);
        Console.WriteLine("SystemProperties.native_set(" + key + "," + def + ")");

        JavaHelper.ReturnVoid(MethodFrameStack, GlobalStack);
    }

    [AndroidNativeMethodAttribute("android/os/SystemProperties", "native_add_change_callback-()V")]
    public void native_add_change_callback(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        
        Console.WriteLine("SystemProperties.native_add_change_callback()");

        JavaHelper.ReturnVoid(MethodFrameStack, GlobalStack);
    }
}
#endregion

#region Trace
[AndroidNativeMethodAttribute("android/os/Trace")]
public class Trace : AndroidINativeMethod
{
    [AndroidNativeMethodAttribute("android/os/Trace", "nativeGetEnabledTags-()J")]
    public void nativeGetEnabledTags(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        Console.WriteLine("Trace.nativeGetEnabledTags()");
        JavaHelper.ReturnLargeValue(MethodFrameStack, GlobalStack, 0);
    }
}
#endregion

#region VMRuntime
[AndroidNativeMethodAttribute("dalvik/system/VMRuntime")]
public class VMRuntime : AndroidINativeMethod
{
    [AndroidNativeMethodAttribute("dalvik/system/VMRuntime", "is64Bit-()Z")]
    public void is64Bit(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        Console.WriteLine("VMRuntime.is64Bit()");
        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack, 0);
    }

    [AndroidNativeMethodAttribute("dalvik/system/VMRuntime", "newUnpaddedArray-(Ljava/lang/Class;I)Ljava/lang/Object;")]
    public void newUnpaddedArray(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        int typeClassObjAddr = args[1];
        int length = args[2];
        if (length < 0)
        {
            //yield return Executor.ThrowJavaException(MethodFrameStack, GlobalStack, "java/lang/NegativeArraySizeException");
            //Executor.ActiveException = thisFrame.Stack[0];
            //yield break;
            throw new Exception();
        }
        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack, Heap.CreateArray(4, length, typeClassObjAddr));
        Console.WriteLine("VMRuntime.newUnpaddedArray()");
    }

    [AndroidNativeMethodAttribute("dalvik/system/VMRuntime", "registerNativeAllocation-(I)V")]
    public void registerNativeAllocation(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        Console.WriteLine("VMRuntime.registerNativeAllocation("+args[0]+")");
        JavaHelper.ReturnVoid(MethodFrameStack, GlobalStack);
    }
}
#endregion

#region MessageQueue
[AndroidNativeMethodAttribute("android/os/MessageQueue")]
public class MessageQueue : AndroidINativeMethod
{
    [AndroidNativeMethodAttribute("android/os/MessageQueue", "nativeInit-()J")]
    public void nativeInit(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        Console.WriteLine("MessageQueue.nativeInit()");
        JavaHelper.ReturnLargeValue(MethodFrameStack, GlobalStack, GameData.MessageQueuePtr);
    }

    [AndroidNativeMethodAttribute("android/os/MessageQueue", "nativePollOnce-(JI)V")]
    public void nativePollOnce(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        Console.WriteLine("MessageQueue.nativePollOnce()");
        JavaHelper.ReturnVoid(MethodFrameStack, GlobalStack);
    }
}
#endregion

#region Binder
[AndroidNativeMethodAttribute("android/os/Binder")]
public class Binder : AndroidINativeMethod
{
    [AndroidNativeMethodAttribute("android/os/Binder", "init-()V")]
    public void init(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        Console.WriteLine("Binder.init()");
        JavaHelper.ReturnVoid(MethodFrameStack, GlobalStack);
    }

    [AndroidNativeMethodAttribute("android/os/Binder", "clearCallingIdentity-()J")]
    public void clearCallingIdentity(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        Console.WriteLine("Binder.clearCallingIdentity()");
        int value = 0;
        JavaHelper.ReturnLargeValue(MethodFrameStack, GlobalStack, value);
    }

    [AndroidNativeMethodAttribute("android/os/Binder", "flushPendingCommands-()V")]
    public void flushPendingCommands(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        Console.WriteLine("Binder.flushPendingCommands()");
        JavaHelper.ReturnVoid(MethodFrameStack, GlobalStack);

    }
}
#endregion

#region Os
[AndroidNativeMethodAttribute("android/system/Os")]
public class Os : AndroidINativeMethod
{
    [AndroidNativeMethodAttribute("android/system/Os", "getuid-()I")]
    public void getuid(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        Console.WriteLine("Os.getuid()");
        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack,GameData.UID);
    }
}
#endregion

#region conscrypt
[AndroidNativeMethodAttribute("com/android/org/conscrypt/TrustedCertificateStore")]
public class TrustedCertificateStore : AndroidINativeMethod
{
    [AndroidNativeMethodAttribute("com/android/org/conscrypt/TrustedCertificateStore", "SetDefaultUserDirectory-(Ljava/lang/String;)V")]
    public void SetDefaultUserDirectory(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        string Directory = JavaHelper.ReadJavaString(args[0]);
        Console.WriteLine("TrustedCertificateStore.SetDefaultUserDirectory("+ Directory + ")");
        JavaHelper.ReturnVoid(MethodFrameStack, GlobalStack);
    }
}
#endregion

#region conscrypt
[AndroidNativeMethodAttribute("android/os/Process")]
public class Process_ : AndroidINativeMethod
{
    [AndroidNativeMethodAttribute("android/os/Process", "setArgV0-(Ljava/lang/String;)V")]
    public void setArgV0(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        string str = JavaHelper.ReadJavaString(args[0]);
        Console.WriteLine("Process.setArgV0(" + str + ")");
        JavaHelper.ReturnVoid(MethodFrameStack, GlobalStack);
    }
}
#endregion

#region DdmServer
[AndroidNativeMethodAttribute("org/apache/harmony/dalvik/ddmc/DdmServer")]
public class DdmServer : AndroidINativeMethod
{
    [AndroidNativeMethodAttribute("", "nativeSendChunk-(I[BII)V")]
    public void nativeSendChunk(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        Console.WriteLine("DdmServer.nativeSendChunk(" + args[0] + ")");
        JavaHelper.ReturnVoid(MethodFrameStack, GlobalStack);
    }
}
#endregion

#region SystemClock
[AndroidNativeMethodAttribute("android/os/SystemClock")]
public class SystemClock : AndroidINativeMethod
{
    [AndroidNativeMethodAttribute("", "uptimeMillis-()J")]
    public void uptimeMillis(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        long time= Environment.TickCount- AndroidNativeMethodFactory.TickCount;
        Console.WriteLine("SystemClock.uptimeMillis() return "+ time);
        JavaHelper.ReturnLargeValue(MethodFrameStack, GlobalStack, time);
    }
}
#endregion

#region BinderInternal
[AndroidNativeMethodAttribute("com/android/internal/os/BinderInternal")]
public class BinderInternal : AndroidINativeMethod
{
    public static int service;
    [AndroidNativeMethodAttribute("", "getContextObject-()Landroid/os/IBinder;")]
    public void getContextObject(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        if(service==0)
        service = Program.Execution("base.service.Service").Item2;
        Console.WriteLine("BinderInternal.getContextObject() return " + service);
        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack, service);
    }
}
#endregion

#region AssetManager
[AndroidNativeMethodAttribute("android/content/res/AssetManager")]
public class AssetManager : AndroidINativeMethod
{
    [AndroidNativeMethodAttribute("", "init-(Z)V")]
    public void init(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        Console.WriteLine("AssetManager.init()");
        JavaHelper.ReturnVoid(MethodFrameStack, GlobalStack);
    }

    [AndroidNativeMethodAttribute("", "getNativeStringBlock-(I)J")]
    public void getNativeStringBlock(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        int id =Resources.Keys.ElementAt(args[1]);
        Console.WriteLine("AssetManager.getNativeStringBlock() return "+id);
        JavaHelper.ReturnLargeValue(MethodFrameStack, GlobalStack,id);
    }

    [AndroidNativeMethodAttribute("", "getStringBlockCount-()I")]
    public void getStringBlockCount(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        int count = Resources.Count;
        Console.WriteLine("AssetManager.getStringBlockCount() return "+ count);
        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack, count);
    }

    [AndroidNativeMethodAttribute("", "setConfiguration-(IILjava/lang/String;IIIIIIIIIIIIII)V")]
    public void setConfiguration(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        string str = JavaHelper.ReadJavaString(args[3]);

        Console.WriteLine("AssetManager.setConfiguration("+str+")");
        JavaHelper.ReturnVoid(MethodFrameStack, GlobalStack);
    }

    public static Dictionary<int, ResourceData> Resources = new Dictionary<int, ResourceData>()
    {
        {2130903050,new ResourceData(0,"game_host_view.xml") }
    };

    [AndroidNativeMethodAttribute("", "loadResourceValue-(ISLandroid/util/TypedValue;Z)I")]
    public void loadResourceValue(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        int block = 0;
        int ident = args[1];
        int density = args[2];
        int outValue = args[3];
        HeapObject heapObject = Heap.GetObject(outValue);
        int type = heapObject.GetField("type", "I");
        int newType = 16;
        if(Resources.ContainsKey(ident))
        {
            block = Resources[ident].id;
            newType = 3;
            heapObject.SetField("assetCookie", "I", ident);
        }
        heapObject.SetField("type", "I", newType);
        int resolveRefs = args[4];
        Console.WriteLine("AssetManager.loadResourceValue("+ident+","+density+") return "+block);
        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack, block);
    }

    [AndroidNativeMethodAttribute("", "getAssignedPackageIdentifiers-()Landroid/util/SparseArray;")]
    public void getAssignedPackageIdentifiers(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        var SparseArray= Program.Execution("android.util.SparseArray");

        Console.WriteLine("AssetManager.getAssignedPackageIdentifiers() ");

        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack,SparseArray.Item2);
    }

    [AndroidNativeMethodAttribute("", "openXmlAssetNative-(ILjava/lang/String;)J")]
    public void openXmlAssetNative(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        int cookie = args[1];
        Console.WriteLine("AssetManager.openXmlAssetNative() return "+ cookie);
        JavaHelper.ReturnLargeValue(MethodFrameStack, GlobalStack, cookie);
    }
}
#endregion

#region XmlBlock
[AndroidNativeMethodAttribute("android/content/res/XmlBlock")]
public class XmlBlock : AndroidINativeMethod
{
    [AndroidNativeMethodAttribute("", "nativeGetStringBlock-(J)J")]
    public void nativeGetStringBlock(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        int id = (int)(args[0], args[1]).ToLong();
        Console.WriteLine("XmlBlock.nativeGetStringBlock() return " + id);
        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack, id);
    }

    [AndroidNativeMethodAttribute("", "nativeCreateParseState-(J)J")]
    public void nativeCreateParseState(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        int id = (int)(args[0], args[1]).ToLong();
        Console.WriteLine("XmlBlock.nativeCreateParseState() return " + id);
        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack, id);
    }
}
#endregion

#region StringBlock
[AndroidNativeMethodAttribute("android/content/res/StringBlock")]
public class StringBlock : AndroidINativeMethod
{
    [AndroidNativeMethodAttribute("", "nativeGetSize-(J)I")]
    public void nativeGetSize(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        int id = (int)(args[0], args[1]).ToLong();
        int size = AssetManager.Resources[id].name.Length;
        Console.WriteLine("StringBlock.nativeGetSize() return " + size);
        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack, size);
    }

    [AndroidNativeMethodAttribute("", "nativeGetString-(JI)Ljava/lang/String;")]
    public void nativeGetString(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        int id = (int)(args[0], args[1]).ToLong();
        //int value = AssetManager.Resources[id].name[args[2]];
        int value =JavaHelper.CreateJavaStringLiteral( AssetManager.Resources[id].name);
        Console.WriteLine("StringBlock.nativeGetString() return " + value);
        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack, value);
    }

    [AndroidNativeMethodAttribute("", "nativeGetStyle-(JI)[I")]
    public void nativeGetStyle(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        int id = (int)(args[0], args[1]).ToLong();

        ResourceData resourceData= AssetManager.Resources[id];
        int value = 0;
        Console.WriteLine("StringBlock.nativeGetStyle() return " + value);
        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack, value);
    }
}
#endregion

#region ICU
[AndroidNativeMethodAttribute("libcore/icu/ICU")]
public class ICU : AndroidINativeMethod
{
    [AndroidNativeMethodAttribute("", "addLikelySubtags-(Ljava/lang/String;)Ljava/lang/String;")]
    public void addLikelySubtags(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        string str = JavaHelper.ReadJavaString(args[0]);
        
        Console.WriteLine("ICU.addLikelySubtags() return " + str);
        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack, args[0]);
    }
}
#endregion

#region Locale
[AndroidNativeMethodAttribute("ext/Locale")]
public class Locale : AndroidINativeMethod
{
    [AndroidNativeMethodAttribute("", "adjustLanguageCode-(Ljava/lang/String;)Ljava/lang/String;")]
    public void adjustLanguageCode(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        string str = JavaHelper.ReadJavaString(args[0]);

        Console.WriteLine("Locale.adjustLanguageCode() return " + str);
        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack, args[0]);
    }
}
#endregion

#region Windows
[AndroidNativeMethodAttribute("base/Windows")]
public class Windows : AndroidINativeMethod
{
    [AndroidNativeMethodAttribute("", "GetHeight-()I")]
    public void GetHeight(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        int height = GameGraphics.Ins.Height;
        Console.WriteLine("Windows.GetHeight() return " + height);
        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack, height);
    }

    [AndroidNativeMethodAttribute("", "GetWidth-()I")]
    public void GetWidth(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        int width = GameGraphics.Ins.Width;
        Console.WriteLine("Windows.GetWidth() return " + width);
        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack, width);
    }
}
#endregion

#region Parcel
[AndroidNativeMethodAttribute("android/os/Parcel")]
public class Parcel : AndroidINativeMethod
{
    public static int Id=1;
    public static Dictionary<int, ParcelData> cache = new Dictionary<int, ParcelData>();
    [AndroidNativeMethodAttribute("", "nativeCreate-()J")]
    public void nativeCreate(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        int mNativePtr = Id++;
        if(!cache .ContainsKey(mNativePtr))
        cache.Add(mNativePtr, new ParcelData(mNativePtr));
        Console.WriteLine("Parcel.nativeCreate() return " + mNativePtr);
        JavaHelper.ReturnLargeValue(MethodFrameStack, GlobalStack, mNativePtr);
    }

    [AndroidNativeMethodAttribute("", "nativeWriteInterfaceToken-(JLjava/lang/String;)V")]
    public void nativeWriteInterfaceToken(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        int id = (int)(args[0], args[1]).ToLong();
        string descriptor = JavaHelper.ReadJavaString(args[2]);
        Console.WriteLine("Parcel.nativeWriteInterfaceToken("+ descriptor + ")");
        ParcelData data = cache[id];
        data.descriptor = descriptor;
        JavaHelper.ReturnVoid(MethodFrameStack, GlobalStack);
    }

    [AndroidNativeMethodAttribute("", "nativeWriteString-(JLjava/lang/String;)V")]
    public void nativeWriteString(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        int id = (int)(args[0], args[1]).ToLong();

        string name = JavaHelper.ReadJavaString(args[2]);
        Console.WriteLine("Parcel.nativeWriteString(" + name + ")");
        ParcelData data = cache[id];
        data.name = name;
        JavaHelper.ReturnVoid(MethodFrameStack, GlobalStack);
    }

    [AndroidNativeMethodAttribute("", "nativeEnforceInterface-(JLjava/lang/String;)V")]
    public void nativeEnforceInterface(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        int id = (int)(args[0], args[1]).ToLong();

        string Interface = JavaHelper.ReadJavaString(args[2]);
        Console.WriteLine("Parcel.nativeEnforceInterface(" + Interface + ")");
        ParcelData data = cache[id];
        data.Interface = Interface;
        JavaHelper.ReturnVoid(MethodFrameStack, GlobalStack);
    }

    [AndroidNativeMethodAttribute("", "nativeReadString-(J)Ljava/lang/String;")]
    public void nativeReadString(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        int id = (int)(args[0], args[1]).ToLong();
        ParcelData data = cache[id];

        string name = data.name;
        Console.WriteLine("Parcel.nativeReadString() ");

        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack,JavaHelper.CreateJavaStringLiteral(name));
    }

    [AndroidNativeMethodAttribute("", "nativeReadStrongBinder-(J)Landroid/os/IBinder;")]
    public void nativeReadStrongBinder(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        int id = (int)(args[0], args[1]).ToLong();
        ParcelData data = cache[id];

        int service = data.service;
        Console.WriteLine("Parcel.nativeReadStrongBinder() ");

        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack, service);
    }

    [AndroidNativeMethodAttribute("", "nativeWriteStrongBinder-(JLandroid/os/IBinder;)V")]
    public void nativeWriteStrongBinder(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        int id = (int)(args[0], args[1]).ToLong();
        ParcelData data = cache[id];

        data.service=args[2];
        Console.WriteLine("Parcel.nativeWriteStrongBinder() ");

        JavaHelper.ReturnVoid(MethodFrameStack, GlobalStack);
    }

    [AndroidNativeMethodAttribute("", "nativeWriteInt-(JI)V")]
    public void nativeWriteInt(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        int id = (int)(args[0], args[1]).ToLong();
        ParcelData data = cache[id];

        data.allowIsolated = args[2];
        Console.WriteLine("Parcel.nativeWriteInt() ");

        JavaHelper.ReturnVoid(MethodFrameStack, GlobalStack);
    }

    [AndroidNativeMethodAttribute("", "nativeSetDataPosition-(JI)V")]
    public void nativeSetDataPosition(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        int id = (int)(args[0], args[1]).ToLong();
        ParcelData data = cache[id];

        data.position = args[2];
        Console.WriteLine("Parcel.nativeSetDataPosition() ");

        JavaHelper.ReturnVoid(MethodFrameStack, GlobalStack);
    }

    [AndroidNativeMethodAttribute("", "nativeFreeBuffer-(J)V")]
    public void nativeFreeBuffer(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        int id = (int)(args[0], args[1]).ToLong();
        //cache.Remove(id);
        Id--;
        Console.WriteLine("Parcel.nativeFreeBuffer("+id+") ");

        JavaHelper.ReturnVoid(MethodFrameStack, GlobalStack);
    }

    [AndroidNativeMethodAttribute("", "nativeReadInt-(J)I")]
    public void nativeReadInt(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        int id = (int)(args[0], args[1]).ToLong();
        int value = 0;
        Console.WriteLine("Parcel.nativeReadInt(" + id + ") return:"+ value);
        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack, value);
    }
}

#region Bitmap
[AndroidNativeMethodAttribute("android/graphics/Bitmap")]
public class Bitmap : AndroidINativeMethod
{
    public static long Id;
    public static Dictionary<long, BitmapData> BitmapDatas = new Dictionary<long, BitmapData>();
    [AndroidNativeMethodAttribute("", "nativeCreate-([IIIIIIZ)Landroid/graphics/Bitmap;")]
    public void nativeCreate(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        Id++;
        int data = args[0];
        int v1 = args[1];
        int v2 = args[2];
        int width = args[3];
        int height = args[4];
        int config = args[5];
        int hasAlpha = args[6];
        int buffer = 0;
        int density = 0;
        int isMutable = 0;
        int requestPremultiplied = 0;
        int ninePatchChunk = 0;
        int ninePatchInsets = 0;
        (int, int) nativeBitmap = Id.Split();
        BitmapData bitmapData = new BitmapData(Id, width, height, config, hasAlpha);
        BitmapDatas.Add(Id, bitmapData);
        (ClassFile,int) bitmap = Program.Execution("android/graphics/Bitmap", nativeBitmap.Item1, nativeBitmap.Item2, buffer, width, height, 
            density, isMutable,requestPremultiplied, ninePatchChunk, ninePatchInsets);

        Console.WriteLine("Bitmap.nativeCreate() return " + bitmap.Item2);
        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack, bitmap.Item2);
    }

    [AndroidNativeMethodAttribute("", "nativeRowBytes-(J)I")]
    public void nativeRowBytes(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        long id = (args[0], args[1]).ToLong();
        int RowBytes = BitmapDatas[id].width*4;
        Console.WriteLine("Bitmap.nativeRowBytes() return " + RowBytes);
        JavaHelper.ReturnValue(MethodFrameStack, GlobalStack, RowBytes);
    }

    [AndroidNativeMethodAttribute("", "nativeSetHasAlpha-(JZZ)V")]
    public void nativeSetHasAlpha(HeapObject thisObj, int[] args, Stack<MethodFrame> MethodFrameStack, Memory<int> GlobalStack)
    {
        long id = (args[0], args[1]).ToLong();
        int HasAlpha = args[2];
        Console.WriteLine("Bitmap.nativeSetHasAlpha()");
        JavaHelper.ReturnVoid(MethodFrameStack, GlobalStack);
    }
}
#endregion

public struct BitmapData
{
    public long id;
    public int width;
    public int height;
    public int config;
    public int hasAlpha;

    public BitmapData(long id, int width, int height, int config, int hasAlpha)
    {
        this.id = id;
        this.width = width;
        this.height = height;
        this.config = config;
        this.hasAlpha = hasAlpha;
    }
}

public class ParcelData
{
    public string descriptor;
    public string name;
    public string Interface;
    public int service;
    public int allowIsolated;
    public int position;
    public List<int> value=new List<int>();
    private int mNativePtr;

    public ParcelData(int mNativePtr)
    {
        this.mNativePtr = mNativePtr;
    }
}
#endregion